home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / Hyperion / src / plat_freebsd.c < prev    next >
C/C++ Source or Header  |  1997-02-26  |  9KB  |  485 lines

  1. /*
  2.  * plat_freebsd.c
  3.  *
  4.  * FreeBSD-specific drive control routines.
  5.  *
  6.  * Todd Pfaff, 3/20/94
  7.  *
  8.  */
  9. static char *ident = "@(#)plat_freebsd.c    1.1 3/31/94";
  10.  
  11. #ifdef __FreeBSD__
  12.  
  13. #include <errno.h>
  14. #include <stdio.h>
  15. #include <sys/types.h>
  16. #include <sys/mount.h>
  17. #include <fcntl.h>
  18. #include <sys/param.h>
  19. #include <sys/stat.h>
  20. #include <sys/time.h>
  21. #include <string.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/cdio.h>
  24. #include <sys/scsiio.h>
  25. #include <scsi/scsi_all.h>
  26. #include <scsi/scsi_cd.h>
  27.  
  28. #include "struct.h"
  29.  
  30. #define DEFAULT_CD_DEVICE       "/dev/rcd0d"
  31.  
  32. void *malloc();
  33.  
  34. int    min_volume = 0;
  35. int    max_volume = 128;
  36.  
  37. extern char    *cd_device;
  38.  
  39.  
  40. /*
  41.  * Initialize the drive.  A no-op for the generic driver.
  42.  */
  43. int
  44. gen_init(d)
  45.     struct wm_drive    *d;
  46. {
  47.     return (0);
  48. }
  49.  
  50. /*
  51.  * Get the number of tracks on the CD.
  52.  */
  53. int
  54. gen_get_trackcount(d, tracks)
  55.     struct wm_drive    *d;
  56.     int        *tracks;
  57. {
  58.     struct ioc_toc_header    hdr;
  59.  
  60.     if (ioctl(d->fd, CDIOREADTOCHEADER, &hdr) == -1)
  61.         return (-1);
  62.  
  63.     *tracks = hdr.ending_track - hdr.starting_track + 1;
  64.  
  65.     return (0);
  66. }
  67.  
  68. /*
  69.  * Get the start time and mode (data or audio) of a track.
  70.  *
  71.  * XXX - this should get cached, but that means keeping track of ejects.
  72.  */
  73. int
  74. gen_get_trackinfo(d, track, data, startframe)
  75.     struct wm_drive    *d;
  76.     int        track, *data, *startframe;
  77. {
  78.     struct ioc_read_toc_entry    toc;
  79.     struct cd_toc_entry        toc_buffer;
  80.  
  81.     bzero((char *)&toc_buffer, sizeof(toc_buffer));
  82.     toc.address_format = CD_MSF_FORMAT;
  83.     toc.starting_track = track;
  84.     toc.data_len = sizeof(toc_buffer);
  85.     toc.data = &toc_buffer;
  86.  
  87.     if (ioctl(d->fd, CDIOREADTOCENTRYS, &toc))
  88.         return (-1);
  89.  
  90.     *data = (toc_buffer.control != 0);
  91.  
  92.     *startframe = toc_buffer.addr.msf.minute*60*75 +
  93.         toc_buffer.addr.msf.second * 75 +
  94.         toc_buffer.addr.msf.frame;
  95.  
  96.     return (0);
  97. }
  98.  
  99. /*
  100.  * Get the number of frames on the CD.
  101.  */
  102. int
  103. gen_get_cdlen(d, frames)
  104.     struct wm_drive    *d;
  105.     int        *frames;
  106. {
  107.     int        tmp;
  108.     struct ioc_toc_header        hdr;
  109.     int status;
  110.  
  111.     /*
  112.  
  113.     *** FIX THIS ***
  114.  
  115.     I can't figure out how to find the length of the last track.
  116.     The CDIOREADTOCENTRYS ioctl() in gen_get_trackinfo() returns an
  117.     error if I try to read past the last track returned by the
  118.     CDIOREADTOCHEADER ioctl().  There doesn't seem to be any other
  119.     way in cdio.h to get the length of a track.
  120.  
  121.     This hack simply adds 10 minutes to the start of the last track
  122.     and returns the result as the total cd length.
  123.  
  124.     Todd Pfaff
  125.     03/20/94
  126.  
  127.     */
  128.  
  129.     if (ioctl(d->fd, CDIOREADTOCHEADER, &hdr))
  130.         return (-1);
  131.  
  132.     if(gen_get_trackinfo(d, hdr.ending_track, &tmp, frames) == -1)
  133.         return (-1);
  134.  
  135.     *frames += 10*60*75;
  136.  
  137.     return(0);
  138. }
  139.  
  140. /*
  141.  * Get the current status of the drive: the current play mode, the absolute
  142.  * position from start of disc (in frames), and the current track and index
  143.  * numbers if the CD is playing or paused.
  144.  */
  145. int
  146. gen_get_drive_status(d, oldmode, mode, pos, track, index)
  147.     struct wm_drive    *d;
  148.     enum cd_modes    oldmode, *mode;
  149.     int        *pos, *track, *index;
  150. {
  151.     struct ioc_read_subchannel    sc;
  152.     struct cd_sub_channel_info    scd;
  153.  
  154.     /* If we can't get status, the CD is ejected, so default to that. */
  155.     *mode = EJECTED;
  156.  
  157.     sc.address_format    = CD_MSF_FORMAT;
  158.     sc.data_format        = CD_CURRENT_POSITION;
  159.     sc.track        = 0;
  160.     sc.data_len        = sizeof(scd);
  161.     sc.data            = (struct cd_sub_channel_info *)&scd;
  162.  
  163.     /* Is the device open? */
  164.     if (d->fd < 0)
  165.     {
  166.         switch (wmcd_open(d)) {
  167.         case -1:    /* error */
  168.             return (-1);
  169.  
  170.         case 1:        /* retry */
  171.             return (0);
  172.         }
  173.     }
  174.  
  175.     if (ioctl(d->fd, CDIOCREADSUBCHANNEL, &sc))
  176.         return (0);    /* ejected */
  177.  
  178.     switch (scd.header.audio_status) {
  179.     case CD_AS_PLAY_IN_PROGRESS:
  180.         *mode = PLAYING;
  181. dopos:
  182.         *pos = scd.what.position.absaddr.msf.minute * 60 * 75 +
  183.             scd.what.position.absaddr.msf.second * 75 +
  184.             scd.what.position.absaddr.msf.frame;
  185.         *track = scd.what.position.track_number;
  186.         *index = scd.what.position.index_number;
  187.         break;
  188.  
  189.     case CD_AS_PLAY_PAUSED:
  190.         if (oldmode == PLAYING || oldmode == PAUSED)
  191.         {
  192.             *mode = PAUSED;
  193.             goto dopos;
  194.         }
  195.         else
  196.             *mode = STOPPED;
  197.         break;
  198.  
  199.     case CD_AS_PLAY_COMPLETED:
  200.         *mode = TRACK_DONE; /* waiting for next track. */
  201.         break;
  202.  
  203.     case CD_AS_NO_STATUS:
  204.     case 0:
  205.         *mode = STOPPED;
  206.         break;
  207.     }
  208.  
  209.     return (0);
  210. }
  211.  
  212. /*
  213.  * scale_volume(vol, max)
  214.  *
  215.  * Return a volume value suitable for passing to the CD-ROM drive.  "vol"
  216.  * is a volume slider setting; "max" is the slider's maximum value.
  217.  *
  218.  * On Sun and DEC CD-ROM drives, the amount of sound coming out the jack
  219.  * increases much faster toward the top end of the volume scale than it
  220.  * does at the bottom.  To make up for this, we make the volume scale look
  221.  * sort of logarithmic (actually an upside-down inverse square curve) so
  222.  * that the volume value passed to the drive changes less and less as you
  223.  * approach the maximum slider setting.  The actual formula looks like
  224.  *
  225.  *     (max^2 - (max - vol)^2) * (max_volume - min_volume)
  226.  * v = --------------------------------------------------- + min_volume
  227.  *                           max^2
  228.  *
  229.  * If your system's volume settings aren't broken in this way, something
  230.  * like the following should work:
  231.  *
  232.  *    return ((vol * (max_volume - min_volume)) / max + min_volume);
  233.  */
  234. static int
  235. scale_volume(vol, max)
  236.     int    vol, max;
  237. {
  238.     return ((max * max - (max - vol) * (max - vol)) *
  239.         (max_volume - min_volume) / (max * max) + min_volume);
  240. }
  241.  
  242. /*
  243.  * Set the volume level for the left and right channels.  Their values
  244.  * range from 0 to 100.
  245.  */
  246. int
  247. gen_set_volume(d, left, right)
  248.     struct wm_drive    *d;
  249.     int        left, right;
  250. {
  251.     struct ioc_vol vol;
  252.  
  253.     left = scale_volume(left, 100);
  254.     right = scale_volume(right, 100);
  255.  
  256.     bzero((char *)&vol, sizeof(vol));
  257.  
  258.     vol.vol[LEFT_PORT] = left;
  259.     vol.vol[RIGHT_PORT] = right;
  260.  
  261.     if (ioctl(d->fd, CDIOCSETVOL, &vol))
  262.         return (-1);
  263.  
  264.     return (0);
  265. }
  266.  
  267. /*
  268.  * Pause the CD.
  269.  */
  270. int
  271. gen_pause(d)
  272.     struct wm_drive    *d;
  273. {
  274.     return (ioctl(d->fd, CDIOCPAUSE));
  275. }
  276.  
  277. /*
  278.  * Resume playing the CD (assuming it was paused.)
  279.  */
  280. int
  281. gen_resume(d)
  282.     struct wm_drive    *d;
  283. {
  284.     return (ioctl(d->fd, CDIOCRESUME));
  285. }
  286.  
  287. /*
  288.  * Stop the CD.
  289.  */
  290. int
  291. gen_stop(d)
  292.     struct wm_drive *d;
  293. {
  294.     return (ioctl(d->fd, CDIOCSTOP));
  295. }
  296.  
  297. /*
  298.  * Play the CD from one position to another (both in frames.)
  299.  */
  300. int
  301. gen_play(d, start, end)
  302.     struct wm_drive    *d;
  303.     int        start, end;
  304. {
  305.     struct ioc_play_msf    msf;
  306.  
  307.     msf.start_m    = start / (60*75);
  308.     msf.start_s    = (start % (60*75)) / 75;
  309.     msf.start_f    = start % 75;
  310.     msf.end_m    = end / (60*75);
  311.     msf.end_s    = (end % (60*75)) / 75;
  312.     msf.end_f    = end % 75;
  313.  
  314.     if (ioctl(d->fd, CDIOCSTART))
  315.         return (-1);
  316.  
  317.     if (ioctl(d->fd, CDIOCPLAYMSF, &msf))
  318.         return (-2);
  319.  
  320.     return (0);
  321. }
  322.  
  323. /*
  324.  * Eject the current CD, if there is one.
  325.  */
  326. int
  327. gen_eject(d)
  328.     struct wm_drive    *d;
  329. {
  330.     /* On some systems, we can check to see if the CD is mounted. */
  331.     struct stat    stbuf;
  332.     struct statfs    buf;
  333.  
  334.     if (fstat(d->fd, &stbuf) != 0)
  335.         return (-2);
  336.  
  337.     /* Is this a mounted filesystem? */
  338.     if (fstatfs(stbuf.st_rdev, &buf) == 0)
  339.         return (-3);
  340.  
  341.     return (ioctl(d->fd, CDIOCEJECT));
  342. }
  343.  
  344. /*
  345.  * unscale_volume(cd_vol, max)
  346.  *
  347.  * Given a value between min_volume and max_volume, return the volume slider
  348.  * value needed to achieve that value.
  349.  *
  350.  * Rather than perform floating-point calculations to reverse the above
  351.  * formula, we simply do a binary search of scale_volume()'s return values.
  352.  */
  353. static int
  354. unscale_volume(cd_vol, max)
  355.     int    cd_vol, max;
  356. {
  357.     int    vol = 0, top = max, bot = 0, scaled;
  358.  
  359.     while (bot <= top)
  360.     {
  361.         vol = (top + bot) / 2;
  362.         scaled = scale_volume(vol, max);
  363.         if (cd_vol == scaled)
  364.             break;
  365.         if (cd_vol < scaled)
  366.             top = vol - 1;
  367.         else
  368.             bot = vol + 1;
  369.     }
  370.     
  371.     if (vol < 0)
  372.         vol = 0;
  373.     else if (vol > max)
  374.         vol = max;
  375.  
  376.     return (vol);
  377. }
  378.  
  379. /*
  380.  * Read the initial volume from the drive, if available.  Each channel
  381.  * ranges from 0 to 100, with -1 indicating data not available.
  382.  */
  383. int
  384. gen_get_volume(d, left, right)
  385.     struct wm_drive    *d;
  386.     int        *left, *right;
  387. {
  388.     struct ioc_vol vol;
  389.  
  390.     if (d->fd >= 0)
  391.     {
  392.         bzero((char *)&vol, sizeof(vol));
  393.  
  394.         if (ioctl(d->fd, CDIOCGETVOL, &vol))
  395.             *left = *right = -1;
  396.         else
  397.         {
  398.             *left = unscale_volume(vol.vol[LEFT_PORT], 100);
  399.             *right = unscale_volume(vol.vol[RIGHT_PORT], 100);
  400.         }
  401.     }
  402.     else
  403.         *left = *right = -1;
  404.  
  405.     return (0);
  406. }
  407.  
  408.  
  409. /*
  410.  * Send an arbitrary SCSI command to a device.
  411.  *
  412.  */
  413. int
  414. wm_scsi(d, cdb, cdblen, retbuf, retbuflen, getreply)
  415.     struct wm_drive    *d;
  416.     unsigned char    *cdb;
  417.     int        cdblen;
  418.     void        *retbuf;
  419.     int        retbuflen;
  420.     int        getreply;
  421. {
  422.     return (-1);
  423. }
  424.  
  425.  
  426. /*
  427.  * Open the CD device and figure out what kind of drive is attached.
  428.  */
  429. int
  430. wmcd_open(d)
  431.     struct wm_drive    *d;
  432. {
  433.     int        fd;
  434.     static int    warned = 0;
  435.     char vendor[9], model[17], rev[5];
  436.  
  437.     if (d->fd >= 0)        /* Device already open? */
  438.         return (0);
  439.  
  440.     if (cd_device == NULL)
  441.         cd_device = DEFAULT_CD_DEVICE;
  442.  
  443.     d->fd = open(cd_device, 0);
  444.     if (d->fd < 0)
  445.     {
  446.         if (errno == EACCES)
  447.         {
  448.             if (!warned)
  449.             {
  450.                 fprintf(stderr,
  451.         "As root, please run\n\nchmod 666 %s\n\n%s\n", cd_device,
  452.         "to give yourself permission to access the CD-ROM device.");
  453.                 warned++;
  454.             }
  455.         }
  456.  
  457.         /* No CD in drive. */
  458.         return (1);
  459.     }
  460.  
  461.     if (warned)
  462.     {
  463.         warned = 0;
  464.         fprintf(stderr, "Thank you.\n");
  465.     }
  466.  
  467.     /* Now fill in the relevant parts of the wm_drive structure. */
  468.     fd = d->fd;
  469.  
  470.     vendor[0] = model[0] = rev[0] = '\0';
  471.  
  472.     *d = *(find_drive_struct(vendor, model, rev));
  473.  
  474.     (d->init)(d);
  475.  
  476.     d->fd = fd;
  477.  
  478.     return (0);
  479. }
  480.  
  481. void
  482. keep_cd_open() { }
  483.  
  484. #endif
  485.